package com.jessecoyle.choplifter.client;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.*;

import java.util.EnumSet;

/**
 * Entry point classes define <code>onModuleLoad()</code>
 */
public class MainEntryPoint implements EntryPoint {

    private Canvas canvas;
    Context2d context;
    // mouse positions relative to canvas
    int mouseX, mouseY;
    //timer refresh rate, in milliseconds
    static final int refreshRate = 1000 / 40; // 1000ms/s * 1s/(40 frames)
    static final int height = 20 * 40 * 3;
    static final int width = 20 * 40 * 4;
    double screenPosition = 0.0;
    Vector position = new Vector(20000, height / 2);
    Vector velocity = new Vector(5, 0);

    private enum Direction {

        UP(new Vector(0, -1)), LEFT(new Vector(-1, 0)), DOWN(new Vector(0, 1)), RIGHT(new Vector(1, 0));
        private Vector vec;

        private Direction(Vector vec) {
            this.vec = vec;
        }

        public Vector getVec() {
            return vec;
        }
    }
    private EnumSet<Direction> pressed = EnumSet.noneOf(Direction.class);

    /**
     * This is the entry point method.
     */
    public void onModuleLoad() {

        canvas = Canvas.createIfSupported();
        if (canvas == null) {
            RootPanel.get().add(new Label("Canvas not supported"));
            return;
        }

        RootPanel.get().add(canvas);

        canvas.setWidth("800px");
        canvas.setHeight("600px");
        canvas.setCoordinateSpaceHeight(height);
        canvas.setCoordinateSpaceWidth(width);
        context = canvas.getContext2d();

        // init handlers
        initHandlers();

        // setup timer
        final Timer timer = new Timer() {

            @Override
            public void run() {
                processInput();
                processPhysics();
                render();
            }
        };
        timer.scheduleRepeating(refreshRate);
    }

    private void processInput() {
        for (Direction d : pressed) {
            velocity.add(d.getVec());
        }
        velocity.x = Math.max(Math.min(velocity.x, 20), -20);
        velocity.y = Math.max(Math.min(velocity.y, 20), -20);
    }

    private void processPhysics() {
        position.add(velocity);

        screenPosition = Math.max(Math.min(screenPosition, position.x - width * 1 / 3), position.x - width * 2 / 3);
    }

    private void render() {
        context.setFillStyle("#000000");
        context.fillRect(0, 0, width, height);

        context.setFillStyle("#666666");
        context.beginPath();
        context.moveTo(width * 0 / 4 - screenPosition % (width * 2 / 4), height * 3 / 4);
        context.lineTo(width * 1 / 4 - screenPosition % (width * 2 / 4), height * 1 / 4);
        context.lineTo(width * 2 / 4 - screenPosition % (width * 2 / 4), height * 3 / 4);
        context.lineTo(width * 3 / 4 - screenPosition % (width * 2 / 4), height * 1 / 4);
        context.lineTo(width * 4 / 4 - screenPosition % (width * 2 / 4), height * 3 / 4);
        context.lineTo(width * 5 / 4 - screenPosition % (width * 2 / 4), height * 1 / 4);
        context.lineTo(width * 6 / 4 - screenPosition % (width * 2 / 4), height * 3 / 4);
        context.closePath();
        context.fill();

        context.setFillStyle("#999999");
        context.fillRect(0, height * 3 / 4, width, height / 4);

        context.setFillStyle("#FFFFFF");
        context.fillRect(position.x - 150 - screenPosition, position.y - 150, 300, 300);
    }

    void initHandlers() {
        canvas.addKeyDownHandler(new KeyDownHandler() {

            public void onKeyDown(KeyDownEvent event) {
                if (event.isLeftArrow()) {
                    pressed.add(Direction.LEFT);
                } else if (event.isRightArrow()) {
                    pressed.add(Direction.RIGHT);
                } else if (event.isUpArrow()) {
                    pressed.add(Direction.UP);
                } else if (event.isDownArrow()) {
                    pressed.add(Direction.DOWN);
                }
            }
        });

        canvas.addKeyUpHandler(new KeyUpHandler() {

            public void onKeyUp(KeyUpEvent event) {
                if (event.isLeftArrow()) {
                    pressed.remove(Direction.LEFT);
                } else if (event.isRightArrow()) {
                    pressed.remove(Direction.RIGHT);
                } else if (event.isUpArrow()) {
                    pressed.remove(Direction.UP);
                } else if (event.isDownArrow()) {
                    pressed.remove(Direction.DOWN);
                }
            }
        });

        canvas.addKeyPressHandler(new KeyPressHandler() {

            public void onKeyPress(KeyPressEvent event) {
                //To change body of implemented methods use File | Settings | File Templates.
            }
        });




        canvas.addMouseMoveHandler(new MouseMoveHandler() {

            public void onMouseMove(MouseMoveEvent event) {
                mouseX = event.getRelativeX(canvas.getElement());
                mouseY = event.getRelativeY(canvas.getElement());
            }
        });

        canvas.addMouseOutHandler(new MouseOutHandler() {

            public void onMouseOut(MouseOutEvent event) {
                mouseX = -200;
                mouseY = -200;
            }
        });

        canvas.addTouchMoveHandler(new TouchMoveHandler() {

            public void onTouchMove(TouchMoveEvent event) {
                event.preventDefault();
                if (event.getTouches().length() > 0) {
                    Touch touch = event.getTouches().get(0);
                    mouseX = touch.getRelativeX(canvas.getElement());
                    mouseY = touch.getRelativeY(canvas.getElement());
                }
                event.preventDefault();
            }
        });

        canvas.addTouchEndHandler(new TouchEndHandler() {

            public void onTouchEnd(TouchEndEvent event) {
                event.preventDefault();
                mouseX = -200;
                mouseY = -200;
            }
        });

        canvas.addGestureStartHandler(new GestureStartHandler() {

            public void onGestureStart(GestureStartEvent event) {
                event.preventDefault();
            }
        });
    }
}
